﻿namespace Stopwatch.ViewModels
{
    using Stopwatch.Commands;
    using Stopwatch.Controls;
    using Stopwatch.Core;
    using Stopwatch.ViewModels;
    using Stopwatch.Views;
    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;

    public sealed class MainContext : INotifyPropertyChanged
    {
        Context context;
        MainPage page;

        public MainContext(MainPage page)
        {
            this.Splits = new SplitItems();
            this.page = page;
            this.context = Context.Load();
            this.SubEnabled = false;
            this.Stoptimer = Time.Zero;
            this.Watch = Time.Zero;
            this.SubWatch = Time.Zero;

            // buttons initializing.
            this.StartWatchButtonVisibility = Visibility.Visible;
            this.PauseWatchButtonVisibility = Visibility.Collapsed;

            this.StartTimerButtonVisibility = Visibility.Visible;
            this.PauseTimerButtonVisibility = Visibility.Collapsed;

            // register event
            this.context.Watch.OnTick += OnWatchTick;
            this.context.Timer.OnTick += OnTimerTick;
            this.context.Timer.OnCompleted += OnTimerCompleted;

            // restore
            Restore();
        }

        void Restore()
        {
            switch (context.Watch.Status)
            {
                case Status.Started:
                    Watch = context.Watch.Runtime;
                    context.Watch.Start();
                    if (context.Watch.Splits != null && context.Watch.Splits.Count > 0)
                    {
                        Time original = Time.Zero;
                        foreach (var time in context.Watch.Splits)
                        {
                            original += time;
                            SplitItem item = new SplitItem(time);
                            item.OriginalTime = original.ToWatch();
                            Splits.Add(item);
                        }

                        SubWatch = context.Watch.SubRuntime;
                        SubEnabled = true;
                    }

                    StartWatchButtonVisibility = Visibility.Collapsed;
                    PauseWatchButtonVisibility = Visibility.Visible;

                    (WatchResetCommand as Command).IsEnabled = true;
                    (WatchSplitCommand as Command).IsEnabled = true;
                    break;

                case Status.Paused:
                    Watch = context.Watch.Runtime;
                    if (context.Watch.Splits != null && context.Watch.Splits.Count > 0)
                    {
                        Time original = Time.Zero;
                        foreach (var time in context.Watch.Splits)
                        {
                            original += time;
                            SplitItem item = new SplitItem(time);
                            item.OriginalTime = original.ToWatch();
                            Splits.Add(item);
                        }

                        SubWatch = context.Watch.SubRuntime;
                        SubEnabled = true;
                    }

                    PauseWatchButtonVisibility = Visibility.Collapsed;
                    StartWatchButtonVisibility = Visibility.Visible;

                    (WatchResetCommand as Command).IsEnabled = true;
                    break;
            }
        }

        void Dispatcher(Action action)
        {
            page.Dispatcher.BeginInvoke(action);
        }

        #region events handlers

        void OnWatchTick(object sender, EventArgs e)
        {
            var w = sender as IWatch;
            if (w != null)
            {
                Dispatcher(() =>
                {
                    Watch = w.Runtime;

                    if (SubEnabled)
                    {
                        SubWatch = w.SubRuntime;
                    }
                });
            }
        }

        void OnTimerTick(object sender, EventArgs e)
        {
            var timer = sender as ITimer;
            if (timer != null)
            {
                Dispatcher(() => Stoptimer = (timer.Runtime));
#if DEBUG
                System.Diagnostics.Debug.WriteLine(timer.Runtime);
#endif
            }
        }

        void OnTimerCompleted(object sender, EventArgs e)
        {
            Dispatcher(() =>
            {
                Mode = TimerMode.Picker;
                Stoptimer = (Time.Zero);

                PauseTimerButtonVisibility = Visibility.Collapsed;
                StartTimerButtonVisibility = Visibility.Visible;

                timerResetCommand.IsEnabled = false;
            });
        }

        #endregion

        #region Commands

        Command watchStartCommand;
        public ICommand WatchStartCommand
        {
            get
            {
                if (watchStartCommand == null)
                {
                    watchStartCommand = new Command(
                        p =>
                        {
                            context.Watch.Start();

                            StartWatchButtonVisibility = Visibility.Collapsed;
                            PauseWatchButtonVisibility = Visibility.Visible;

                            watchSplitCommand.IsEnabled = true;
                            watchResetCommand.IsEnabled = true;
                        });
                }

                return watchStartCommand;
            }
        }

        Command watchPauseCommand;
        public ICommand WatchPauseCommand
        {
            get
            {
                if (watchPauseCommand == null)
                {
                    watchPauseCommand = new Command(
                        p =>
                        {
                            context.Watch.Pause();

                            watchSplitCommand.IsEnabled = false;

                            PauseWatchButtonVisibility = Visibility.Collapsed;
                            StartWatchButtonVisibility = Visibility.Visible;
                        });
                }

                return watchPauseCommand;
            }
        }

        Command watchSplitCommand;
        public ICommand WatchSplitCommand
        {
            get
            {
                if (watchSplitCommand == null)
                {
                    watchSplitCommand = new Command(
                        p =>
                        {
                            SplitItem item = new SplitItem(context.Watch.Split());
                            Time original = Time.Zero;
                            foreach (var time in context.Watch.Splits)
                            {
                                original += time;
                            }

                            item.OriginalTime = original.ToWatch();
                            Splits.Add(item);
                            SubEnabled = true;
                        });

                    watchSplitCommand.IsEnabled = false;
                }

                return watchSplitCommand;
            }
        }

        Command watchResetCommand;
        public ICommand WatchResetCommand
        {
            get
            {
                if (watchResetCommand == null)
                {
                    watchResetCommand = new Command(
                        p =>
                        {
                            SubEnabled = false;
                            context.Watch.Reset();
                            Splits.Clear();
                            Watch = Time.Zero;
                            SubWatch = Time.Zero;

                            watchResetCommand.IsEnabled = false;
                            watchSplitCommand.IsEnabled = false;

                            PauseWatchButtonVisibility = Visibility.Collapsed;
                            StartWatchButtonVisibility = Visibility.Visible;
                        });

                    watchResetCommand.IsEnabled = false;
                }

                return watchResetCommand;
            }
        }

        Command timerStartCommand;
        public ICommand TimerStartCommand
        {
            get
            {
                if (timerStartCommand == null)
                {
                    timerStartCommand = new Command(
                        p =>
                        {
                            context.Timer.Duration = page.TimerDuration;
                            if (context.Timer.Start())
                            {
                                Mode = TimerMode.Show;

                                StartTimerButtonVisibility = Visibility.Collapsed;
                                PauseTimerButtonVisibility = Visibility.Visible;

                                timerResetCommand.IsEnabled = true;
                            }
                        });
                }

                return timerStartCommand;
            }
        }

        Command timerPauseCommand;
        public ICommand TimerPauseCommand
        {
            get
            {
                if (timerPauseCommand == null)
                {
                    timerPauseCommand = new Command(
                        p =>
                        {
                            context.Timer.Pause();
                            PauseTimerButtonVisibility = Visibility.Collapsed;
                            StartTimerButtonVisibility = Visibility.Visible;
                        });
                }

                return timerPauseCommand;
            }
        }

        Command timerResetCommand;
        public ICommand TimerResetCommand
        {
            get
            {
                if (timerResetCommand == null)
                {
                    timerResetCommand = new Command(
                        p =>
                        {
                            Mode = TimerMode.Picker;
                            context.Timer.Reset();

                            PauseTimerButtonVisibility = Visibility.Collapsed;
                            StartTimerButtonVisibility = Visibility.Visible;

                            timerResetCommand.IsEnabled = false;
                        });

                    timerResetCommand.IsEnabled = false;
                }

                return timerResetCommand;
            }
        }

        #endregion

        #region properties

        #region Splits
        public SplitItems Splits { get; private set; }
        #endregion

        #region SubEnabled
        bool subEnabled;
        public bool SubEnabled
        {
            get { return subEnabled; }
            private set
            {
                if (subEnabled != value)
                {
                    subEnabled = value;
                    NotifyPropertyChanged("SubEnabled");
                }
            }
        }
        #endregion

        #region Watch
        Time watch;
        public Time Watch
        {
            get { return watch; }
            private set
            {
                if (watch != value)
                {
                    watch = value;
                    NotifyPropertyChanged("Watch");
                }
            }
        }
        #endregion

        #region SubWatch
        Time subWatch;
        public Time SubWatch
        {
            get { return subWatch; }
            private set
            {
                if (subWatch != value)
                {
                    subWatch = value;
                    NotifyPropertyChanged("SubWatch");
                }
            }
        }
        #endregion

        #region Stoptimer
        Time stoptimer;
        public Time Stoptimer
        {
            get { return stoptimer; }
            private set
            {
                if (stoptimer != value)
                {
                    stoptimer = value;
                    NotifyPropertyChanged("Stoptimer");
                }
            }
        }
        #endregion

        #region TimerMode
        TimerMode mode;
        public TimerMode Mode
        {
            get { return mode; }
            private set
            {
                if (Mode != value)
                {
                    mode = value;
                    NotifyPropertyChanged("Mode");
                }
            }
        }
        #endregion

        #region TimerReseted
        bool timerReseted;
        public bool TimerReseted
        {
            get { return timerReseted; }
            private set
            {
                if (timerReseted != value)
                {
                    timerReseted = value;
                    NotifyPropertyChanged("TimerReseted");
                }
            }
        }
        #endregion

        #region StartWatchButtonVisibility
        Visibility startWatchButtonVisibility;
        public Visibility StartWatchButtonVisibility
        {
            get { return startWatchButtonVisibility; }
            private set
            {
                if (startWatchButtonVisibility != value)
                {
                    startWatchButtonVisibility = value;
                    NotifyPropertyChanged("StartWatchButtonVisibility");
                }
            }
        }
        #endregion

        #region PauseWatchButtonVisibility
        Visibility pauseWatchButtonVisibility;
        public Visibility PauseWatchButtonVisibility
        {
            get { return pauseWatchButtonVisibility; }
            private set
            {
                if (pauseWatchButtonVisibility != value)
                {
                    pauseWatchButtonVisibility = value;
                    NotifyPropertyChanged("PauseWatchButtonVisibility");
                }
            }
        }
        #endregion

        #region StartTimerButtonVisibility
        Visibility startTimerButtonVisibility;
        public Visibility StartTimerButtonVisibility
        {
            get { return startTimerButtonVisibility; }
            private set
            {
                if (startTimerButtonVisibility != value)
                {
                    startTimerButtonVisibility = value;
                    NotifyPropertyChanged("StartTimerButtonVisibility");
                }
            }
        }
        #endregion

        #region PauseTimerButtonVisibility
        Visibility pauseTimerButtonVisibility;
        public Visibility PauseTimerButtonVisibility
        {
            get { return pauseTimerButtonVisibility; }
            private set
            {
                if (pauseTimerButtonVisibility != value)
                {
                    pauseTimerButtonVisibility = value;
                    NotifyPropertyChanged("PauseTimerButtonVisibility");
                }
            }
        }
        #endregion

        #endregion

        #region PropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}